﻿using NLua;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace TextAutoEdit
{
    struct LuaType
    {
        public const string String = "String";
        public const string Int = "Int64";
        public const string Double = "Double";
        public const string LuaTable = "LuaTable";
    }

    internal class MLua
    {
        private static int _curIndex = 0;
        private static List<Lua> _luas = new List<Lua>() { MLuaEvn.GetLua() };
        private static Stack<int> _emptyIndexStack = new Stack<int>();

        private int _index;
        public int Index { get => _index; }

        internal MLua()
        {
            if (_emptyIndexStack.Count > 0)
                _index = _emptyIndexStack.Pop();
            else
                _index = _curIndex++;
        }

        public static MLua CreateMLua()
        {
            MLua mLua = new MLua();
            Lua lua = MLuaEvn.GetLua();

            if (_luas.Count <= mLua.Index)
                _luas.Add(lua);
            else
                _luas.Insert(mLua.Index, lua);
            return mLua;
        }

        public void Close()
        {
            _luas[Index].Close();
            _luas[Index] = null;
            _index = 0;
        }

        public static void DoString(string str)
        {
            try
            {
                _luas[0].DoString(str);
            }
            catch (Exception e)
            {
                MLog.Log($"请检查其正确性 \r\n{str}\r\n{e.Message}");
            }
            
        }

        public static async Task ReloadAsync()
        {
            await Task.Run(() =>
            {
                foreach (var lua in _luas)
                {
                    MLuaEvn.LoadFile(lua);
                }
            });

            MLog.Log("重加载完成！");
        }


        public static string GetStringValue(string propertyName)
        {
            return _luas[0].GetString(propertyName);
        }

        public static async Task<object[]> ExFuncAsync<T1>(string funcName, T1 arg1)
        {
            (object[], string) ret = await Task.Run(() =>
            {
                LuaFunction func = _luas[0].GetFunction(funcName);
                try
                {
                    return (func.Call(arg1), $"{funcName}执行完成！");
                }
                catch (Exception e)
                {
                    return (default, $"请检查函数\"{funcName}\"的正确性！\r\n{e.Message}");
                }
            });
            MLog.Log(ret.Item2);
            return ret.Item1;
        }

        public async void DoActionAsync(string funcName)
        {
            await Task.Run(() =>
            {
                LuaFunction func = _luas[_index].GetFunction(funcName);

                if (func == null)
                {

                }
                else
                {
                    func.Call();
                }
                return func != null;
            });
        }

        public async void DoActionAsync<T1>(string funcName, T1 arg1)
        {
            await Task.Run(() =>
            {
                LuaFunction func = _luas[_index].GetFunction(funcName);

                if (func == null)
                {

                }
                else
                {
                    func.Call(arg1);
                }

                return func != null;
            });
        }

        public async void DoActionAsync<T1, T2>(string funcName, T1 arg1, T2 arg2)
        {
            await Task.Run(() =>
            {
                LuaFunction func = _luas[_index].GetFunction(funcName);

                if (func == null)
                {

                }
                else
                {
                    func.Call(arg1, arg2);
                }

                return func != null;
            });
        }

        public async void DoActionAsync<T1, T2, T3>(string funcName, T1 arg1, T2 arg2, T3 arg3)
        {
            await Task.Run(() =>
           {
               LuaFunction func = _luas[_index].GetFunction(funcName);

               if (func == null)
               {

               }
               else
               {
                   func.Call(arg1, arg2, arg3);
               }

               return func != null;
           });
        }

        public async Task<V> DoFuncAsync<V>(string funcName)
        {
            return await Task.Run(() =>
            {
                LuaFunction func = _luas[_index].GetFunction(funcName);

                if (func == null)
                {
                    return default;
                }
                else
                {
                    return WrapRet<V>(func.Call());
                }
            });
        }

        public async Task<V> DoFuncAsync<T1, V>(string funcName, T1 arg1)
        {
            return await Task.Run(() =>
            {
                LuaFunction func = _luas[_index].GetFunction(funcName);

                if (func == null)
                {
                    return default;
                }
                else
                {
                    return WrapRet<V>(func.Call(arg1));
                }
            });
        }

        public async Task<V> DoFuncAsync<T1, T2, V>(string funcName, T1 arg1, T2 arg2)
        {
            return await Task.Run(() =>
            {
                LuaFunction func = _luas[_index].GetFunction(funcName);

                if (func == null)
                {
                    return default;
                }
                else
                {
                    return WrapRet<V>(func.Call(arg1, arg2));
                }
            });
        }

        public async Task<V> DoActionAsync<T1, T2, T3, V>(string funcName, T1 arg1, T2 arg2, T3 arg3)
        {
            return await Task.Run(() =>
            {
                LuaFunction func = _luas[_index].GetFunction(funcName);

                if (func == null)
                {
                    return default;
                }
                else
                {
                    return WrapRet<V>(func.Call(arg1, arg2, arg3));
                }
            });
        }

        private static T WrapRet<T>(object[] rets)
        {
            if (rets == null || rets.Length <= 0)
            {
                return default;
            }

            if (rets.Length == 1)
            {
                return (T)rets[0];
            }
            else
            {
                return (T)rets[0];
                //T wrapRet = (T)rets[0];

                //foreach (var ret in rets)
                //{
                //    switch (ret)
                //    {
                //        case LuaType.String:

                //            break;
                //        case LuaType.Double:

                //            break;
                //        case LuaType.Int:

                //            break;
                //        case LuaType.LuaTable:

                //            break;
                //    }
                //}

                //return wrapRet;
            }

        }
    }
}
